#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <jsoncpp/json/json.h>
enum
{
    USAGE_ERR = 0,
    SOCKET_ERR,
    BIND_ERR,
    LISTEN_ERR
};

#define SEP " "
#define SEP_LEN strlen(SEP)
#define LINE_SEP "\r\n"
#define LINE_SEP_LEN strlen(LINE_SEP)

// Request:  对象/数据结构 → 序列化 → 字节流 → 添加报头 → 网络发送
// Response: 网络接收 → 解析报头 → 字节流 → 反序列化 → 对象/数据结构

//"x op y"->"content_len"\r\n"x op y"\r\n
//"exitcode result"->"content_len"\r\n"exitcode result"\r\n

std::string enLength(const std::string &text) // 添加报头(还有\r\n)（序列化之后）----属于协议的定制
{
    std::string send_string = std::to_string(text.size()); //-----content_len
    send_string += LINE_SEP;
    send_string += text;
    send_string += LINE_SEP;

    return send_string;
}

//"content_len"\r\n"x op y"\r\n->"x op y"
//"content_len"\r\n"exitcode result"\r\n->"exitcode result"
bool deLength(const std::string &package, std::string *text) // 去掉报头(得到的是有效的数据)
{
    auto pos = package.find(LINE_SEP);
    if (pos == std::string::npos)
        return false;
    std::string text_len_string = package.substr(0, pos);
    int text_len = std::stoi(text_len_string);
    *text = package.substr(pos + LINE_SEP_LEN, text_len);
    return true;
}

class Request // 请求
{
public:
    Request()
        : x(0), y(0), op(0)
    {
    }
    Request(int x_, int y_, char op_)
        : x(x_), y(y_), op(op_)
    {
    }

    // 序列化--将对象的状态信息转换为可以存储或传输的格式的过程
    // 1.自己写
    // 2.用现成的
    bool serialize(std::string *out)
    {
#ifdef MYSELF
        *out = "";
        // 也就是结构化->"x op y"
        std::string x_string = std::to_string(x);
        std::string y_string = std::to_string(y);
        *out = x_string;
        *out += SEP;
        *out += op;
        *out += SEP;
        *out += y_string;
#else
        // 将结构化的数据放入到Json::Value----万能对象中
        //Json::Value 类型
        Json::Value root;
        root["first"] = x;
        root["second"] = y;
        root["oper"] = op;//json 中插入 char 类型会发生隐式类型转换,char -> int 
                                                                //如'A' -> 65

        // 创建writer对象
        Json::FastWriter writer;
        // Json::StyledWriter writer;

        // writer.write返回的是字符串，也就是序列化
        *out = writer.write(root);
#endif

        return true;
    }

    // 反序列化--将序列化后的数据还原为对象的过程。
    bool deserialize(const std::string &in)
    {
#ifdef MYSELF
        // 也就是"x op y"->结构化
        auto left = in.find(SEP);
        auto right = in.rfind(SEP); // 返回的是下标

        if (left == std::string::npos || right == std::string::npos)
            return false;
        if (left == right)
            return false;
        if (right - (left + SEP_LEN) != 1)
            return false;

        std::string x_string = in.substr(0, left);
        std::string y_string = in.substr(right + SEP_LEN); // substr 的第二个参数是长度，不是下标。

        if (x_string.empty())
            return false;
        if (y_string.empty())
            return false;
        x = std::stoi(x_string);
        y = std::stoi(y_string);
        op = in[left + SEP_LEN];
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        x = root["first"].asInt();
        y = root["second"].asInt();
        op = root["op"].asInt();
#endif
        return true;
    }

public:
    //"x op y"
    int x;
    int y;
    char op;
};

class Response // 响应
{
public:
    Response()
        : exitcode(0), result(0)
    {
    }
    Response(int exitcode_, int result_)
        : exitcode(exitcode_), result(result_)
    {
    }
    // 序列化
    bool serialize(std::string *out)
    {
#ifdef MYSELF

        *out = "";
        std::string ec_string = std::to_string(exitcode);
        std::string res_string = std::to_string(result);

        //"exitcode result"

        *out += ec_string;
        *out += SEP;
        *out += res_string;
#else
        Json::Value root;
        root["exitcode"] = exitcode;
        root["result"] = result;

        Json::FastWriter writer;
        *out = writer.write(root);
#endif
        return true;
    }

    // 反序列化
    bool deserialize(const std::string &in)
    {
#ifdef MYSELF
        //"exitcode result"
        auto mid = in.find(SEP);
        if (mid == std::string::npos)
            return false;
        std::string ec_string = in.substr(0, mid);
        std::string res_string = in.substr(mid + SEP_LEN);
        if (ec_string.empty() || res_string.empty())
            return false;

        exitcode = std::stoi(ec_string);
        result = std::stoi(res_string);
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        exitcode = root["exitcode"].asInt();
        result = root["result"].asInt();
#endif
        return true;
    }

public:
    int exitcode; // 0:计算成功，!0表示计算失败,具体是多少，定好标准
    int result;   // 计算成功的结果
};

//"content_len"\r\n"x op y"\r\n"
bool recvPackage(int sock, std::string &inbuffer, std::string *text) // 处理数据以获得一个完整的报文
{
    char buffer[1024];
    while (true)
    {                                                      // 读取客户端/服务器发来的讯息---读取信息
        ssize_t n = recv(sock, buffer, sizeof(buffer), 0); // 这里的读取结果不一定是//"content_len"\r\n"x op y"\r\n"（一个完整的报文），
                                                           // 也有可能是"content_len"\r\n"x op y"\r\n""content_len"\r\n"x op y"\r\n"
                                                           // 或者"content_len"\r\n"x or,这也是为什么inbuffer += buffer;的原因
        if (n > 0)
        {
            buffer[n] = 0;
            inbuffer += buffer;
            // 分析处理
            auto pos = inbuffer.find(LINE_SEP);
            if (pos == std::string::npos)
                continue;                                                         // 如果没有找到分隔符就接着找
            std::string text_len_string = inbuffer.substr(0, pos);                //"content_len"
            int text_len = std::stoi(text_len_string);                            // 有效内容的长度
            int total_len = text_len + text_len_string.size() + 2 * LINE_SEP_LEN; // 一个完整报文的长度
            // text_len_string + "\r\n" + text + "\r\n" > inbuffer.size()----这时说明还没有读取到一个完整的报文
            if (total_len > inbuffer.size())
                continue;

            std::cout << "处理前inbuffer：\n"
                      << inbuffer << std::endl;
            // 到这里时就说明至少有一个完整报文了
            *text = inbuffer.substr(0, total_len);

            inbuffer.erase(0, total_len);

            std::cout << "处理后inbuffer：\n"
                      << inbuffer << std::endl;
            break;
        }
        else
        {
            return false;
        }
    }
    return true;
}

// bool recvRequestAll(int sock, std ::vector<std ::string> *out)//可以将得到的报文统一的放到一个数组当中进行管理
// {
//     std ::string line;
//     while (recvRequest(sock, &line))
//         out->push_back(line);
// }